package com.xbongbong.saas.help;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.pojo.InfoArrPojo;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.pojo.AddMuchFieldPojo;
import com.xbongbong.paas.pojo.dto.FormDataUpdateGetDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.vo.FormDataAddVO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.fund.enums.ModelTypeEnum;
import com.xbongbong.pro.enums.fund.enums.PeriodTypeEnum;
import com.xbongbong.pro.fundset.pojo.PeriodFilterPojo;
import com.xbongbong.pro.payment.pojo.PaymentTransitionPojo;
import com.xbongbong.pro.payment.pojo.dto.PaymentDTO;
import com.xbongbong.pro.product.pojo.dto.CostRecalculationDTO;
import com.xbongbong.pro.rabbitmq.producer.CostRecalculationProducer;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.InvoiceConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentTaskEntityExt;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.ContractOutstockEnum;
import com.xbongbong.saas.enums.business.InvoiceEnum;
import com.xbongbong.saas.enums.business.OrderEnum;
import com.xbongbong.saas.enums.business.PaymentDistributorEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.enums.dictionary.PaymentStatusEnum;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.PaymentModel;
import com.xbongbong.saas.service.CustomerStatementService;
import com.xbongbong.saas.service.FundSetService;
import com.xbongbong.saas.service.PaymentService;
import com.xbongbong.saas.service.toolbox.help.FundMoneyHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;

/**
 * @author yuqian
 */
@Component
public class ReceivablesHelper extends BasicHelper{

    @Resource
    private SaasSaveHelp saasSaveHelp;
    @Resource
    private FundSetService fundSetService;
    @Resource
    private PaymentService paymentService;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private ContractModel contractModel;
    @Resource
    private PaymentModel paymentModel;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private CustomerStatementService customerStatementService;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private FundMoneyHelp fundMoneyHelp;
    @Resource
    private EsHelper esHelper;
    @Resource
    private SaasCustomerStatementHelper saasCustomerStatementHelper;
    @Resource
    private CostRecalculationProducer costRecalculationProducer;
    private static  final Logger LOG = LoggerFactory.getLogger(ReceivablesHelper.class);

    public void createReceivablesHandle(SaasFormSaveDTO saasFormSaveDTO,Long modelType,  List<PaymentTaskEntityExt> paymentTaskEntityExtList) throws XbbException{
        Integer distributorMark = saasFormSaveDTO.getDistributorMark();
        String corpid = saasFormSaveDTO.getCorpid();
        JSONArray amountDetail = saasFormSaveDTO.getAmountDetail();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        PaasFormEntityExt paasFormEntityExt = paasFormModel.getByBusinessType4Distributor(XbbRefTypeEnum.PAYMENT.getCode(), corpid, distributorMark, null);
        if (Objects.isNull(paasFormEntityExt)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_NOT_EXIST);
        }
        Long formId = paasFormEntityExt.getId();
        PaymentDTO paymentDTO = new PaymentDTO();
        BeanUtil.copyProperties(saasFormSaveDTO, paymentDTO);
        paymentDTO.setBusinessType(XbbRefTypeEnum.PAYMENT.getCode());
        paymentDTO.setSysLong10(modelType);
        paymentDTO.setAppId(paasFormEntityExt.getAppId());
        paymentDTO.setMenuId(paasFormEntityExt.getMenuId());
        paymentDTO.setFormId(formId);
        PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
        paymentDTO.setDistributorMark(paasFormExplainEntity.getDistributorMark());
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains());
        createReceivables(paymentDTO, newPaasFormDataEntity,amountDetail, explainMap,saasFormSaveDTO.getBusinessType() , paymentTaskEntityExtList);
    }

    /**
     * 从其它
     * @param paymentDTO
     * @param paasFormDataEntity
     * @param explainMap
     * @throws XbbException
     */
    public void createReceivables(PaymentDTO paymentDTO, PaasFormDataEntity paasFormDataEntity,JSONArray amountDetail, Map<String,
            FieldAttrEntity> explainMap,Integer refBusinessType,   List<PaymentTaskEntityExt> paymentTaskEntityExtList) throws XbbException{
        String corpid = paymentDTO.getCorpid();
        Long formId = paymentDTO.getFormId();
        Long modelType = paymentDTO.getSysLong10();
        FieldAttrEntity fieldAttrEntity = explainMap.get(PaymentEnum.PAYMENT_NO.getAttr());
        String serialNo = "";
        boolean isCreatedReceivable = false;

        List<AddMuchFieldPojo> addBatchList = new ArrayList<>();
        JSONObject parentData = paasFormDataEntity.getData();

        //查询合同的团队
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("del", 0);
        FormDataAddVO formDataAddVO = null;
        Integer businessType = XbbRefTypeEnum.PAYMENT.getCode();
        if(Objects.equals(refBusinessType,XbbRefTypeEnum.INVOICE.getCode())){
            if(Objects.equals(modelType,ModelTypeEnum.INVOICE.getCode())) {
                //应收金额取以下三者最小值
                //=合同"未收金额"
                //=销项发票的"开票金额"
                //=合同金额-(核销预收款金额-红冲核销预收款金额)-(已核销金额-红冲已核销金额)-已坏账金额-（应收款金额-应收款已回款金额-应收款已坏账金额-红冲应收款金额）
                Map<Long ,Double> invoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if(CollectionsUtil.isNotEmpty(amountDetail)){
                    for(int i=0;i<amountDetail.size();i++){
                        //等 销项发票 格式改造 上线再开启
                        JSONObject amountObject = amountDetail.getJSONObject(i);
                        JSONArray contractArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(amountObject,InvoiceConstant.CONTRACT,new JSONArray());
                        Long contractId = contractArray.getJSONObject(BasicConstant.ZERO).getLong(BasicConstant.ID);
                        Double invoiceAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(amountObject, InvoiceConstant.INVOICE_AMOUNT,0D);
                        invoiceMap.put(contractId,invoiceAmount);
                        /*JSONObject amountObject = amountDetail.getJSONObject(i);
                        JSONArray contractArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(amountObject,InvoiceEnum.CONTRACT_ID.getAttr(),new JSONArray());
                        Long contractId = contractArray.getJSONObject(BasicConstant.ZERO).getLong(BasicConstant.ID);
                        Double invoiceAmount = saasUpdateHelp.getDoubleOrDefaultFromFormData(amountObject, InvoiceEnum.TOTAL_MONEY.getAttr(),0D);
                        invoiceMap.put(contractId,invoiceAmount);*/
                    }
                }

                Long customerId = FastJsonHelper.getLongOrDefaultFromFormData(parentData,InvoiceEnum.CUSTOMER_NAME.getAttr(),0L);
                JSONArray contractIds = FastJsonHelper.getJsonArrOrDefaultFromFormData(parentData,InvoiceEnum.CONTRACT_ID.getAttr(),new JSONArray());
                String customerName = FastJsonHelper.getStringOrDefaultFromFormData(parentData,InvoiceEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(),"");
                Long invoiceDate = FastJsonHelper.getLongOrDefaultFromFormData(parentData,InvoiceEnum.INVOICE_DATE.getAttr(),0L);
                List<Long> list = JSONArray.parseArray(contractIds.toJSONString(),Long.class);
                param.put("idIn",list);
                List<ContractEntityExt> contractEntityExtList = contractModel.findEntitys(param);
                if(CollectionsUtil.isNotEmpty(contractEntityExtList)) {
                    for (ContractEntityExt contractEntityExt : contractEntityExtList) {
                        JSONObject contractObject = contractEntityExt.getData();
                        //合同"未收金额"
                        Double unFinishAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractObject, ContractEnum.UN_FINISH_AMOUNT.getAttr(),0D);
                        //合同金额
                        Double contractAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractObject, ContractEnum.AMOUNT.getAttr(),0D);
                        //销项发票的"开票金额"
                        Double amount = invoiceMap.getOrDefault(contractEntityExt.getId(),0D);
                        //计算可添加应收款的第三种情况
                        Double  contractCanAddMoney = calculateThreeSituation(corpid, contractEntityExt.getId(), contractAmount);
                        //比较合同未收金额、销项发票的开票金额、合同金额-(核销预收款金额-红冲核销预收款金额)-(已核销金额-红冲已核销金额)-已坏账金额-（应收款金额-应收款已回款金额-应收款已坏账金额-红冲应收款金额）几个之间的最小值
                        List<Double> compareList = Arrays.asList(amount, unFinishAmount, contractCanAddMoney);
                        amount = Collections.min(compareList);
                        if(amount<=BasicConstant.ZERO){
                            continue;
                        }
                        serialNo = saasSaveHelp.getSerialNo(serialNo, corpid, formId, fieldAttrEntity);
                        //计算应收帐期
                        PeriodFilterPojo periodFilterPojo = fundSetService.getPeriodFilter4Payment(corpid,invoiceDate,customerId,contractEntityExt.getId(),null);
                        AddMuchFieldPojo addMuchFieldPojo = new AddMuchFieldPojo();
                        addMuchFieldPojo.setSysLong10(ModelTypeEnum.INVOICE.getCode());
                        addMuchFieldPojo.setSerialNo(serialNo);

                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put(PaymentEnum.AMOUNT.getAttr(), amount);
                        //取来源单据的"开票日期"
                        jsonObject.put(PaymentEnum.GENERATION_DATE.getAttr(),periodFilterPojo.getGenerationTime());
                        JSONObject generationJson = new JSONObject();
                        generationJson.put(BasicConstant.TYPE,periodFilterPojo.getType());
                        generationJson.put(PeriodTypeEnum.MONTH.getAlias(),periodFilterPojo.getMonth());
                        generationJson.put(PeriodTypeEnum.DAY_AFTER.getAlias(),periodFilterPojo.getDay());
                        jsonObject.put(PaymentEnum.RECEIVABLE_PERIOD.getAttr(),generationJson.toJSONString());
                        jsonObject.put(PaymentEnum.ESTIMATE_TIME.getAttr(),periodFilterPojo.getEstimateTime());
                        jsonObject.put(PaymentEnum.SOURCE.getAttr(),paasFormDataEntity.getId());
                        jsonObject.put(PaymentEnum.CUSTOMER.getAttr(),customerId);
                        jsonObject.put(PaymentEnum.CONTRACT.getAttr(), contractEntityExt.getId());
                        jsonObject.put(PaymentEnum.STATUS.getAttr(), PaymentStatusEnum.UN_RECEIVABLES.getCode());
                        jsonObject.put(PaymentEnum.CUSTOMER_LINK_TEXT.getAttr(),customerName);
                        jsonObject.put(PaymentEnum.CONTRACT_LINK_TEXT.getAttr(), contractEntityExt.getSerialNo());
                        jsonObject.put(PaymentEnum.SOURCE_REF_TYPE.getAttr(),refBusinessType);
                        jsonObject.put(PaymentEnum.SOURCE_LINK_TEXT.getAttr(),paasFormDataEntity.getSerialNo());
                        //把订货单的下单人信息塞入
                        jsonObject.put(PaymentDistributorEnum.ORDERER_ID.getAttr(), contractObject.get(OrderEnum.ORDERER_ID.getAttr()));
                        jsonObject.put(PaymentDistributorEnum.ORDERER.getAttr(), contractObject.get(OrderEnum.ORDERER.getAttr()));
                        //初始化其它字段
                        for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPayment().entrySet()){
                            SaasDataInitHelp.antDataSet(jsonObject,entry.getKey(),entry.getValue());
                        }
                        addMuchFieldPojo.setOwnerId(paasFormDataEntity.getOwnerId());
                        addMuchFieldPojo.setData(jsonObject);
                        addBatchList.add(addMuchFieldPojo);
                    }
                    paymentDTO.setAddBatchList(addBatchList);
                    //应收款保存
                    formDataAddVO = paymentService.pay(paymentDTO);
                    isCreatedReceivable = true;
                }
            }
        } else if (Objects.equals(refBusinessType, XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
            //虽然生成对账单是用应收款生成，但是业务类型用 CONTRACT_OUTSTOCK，用于标识去处理产品相关信息
            businessType = XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode();
            //应收金额取以下三者最小值
            //=合同"未收金额"
            //=销售出库单的"出库金额"
            //=合同金额-(核销预收款金额-红冲核销预收款金额)-(已核销金额-红冲已核销金额)-已坏账金额-（应收款金额-应收款已回款金额-应收款已坏账金额-红冲应收款金额）
            if(Objects.equals(modelType,ModelTypeEnum.OUTSTOCK.getCode())) {
                //销售出库单的"出库金额"
                Double amount = FastJsonHelper.getDoubleOrDefaultFromFormData(parentData, ContractOutstockEnum.TOTAL_MONEY.getAttr(), 0D);
                Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(parentData,ContractOutstockEnum.REF_ID.getAttr(),0L);
                ContractEntityExt contractEntityExt = contractModel.getByKey(contractId,corpid);
                if(Objects.isNull(contractEntityExt)){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404);
                }
                //取合同下 已生成的应收金额
                JSONObject contractObject = contractEntityExt.getData();
                //合同"未收金额"
                Double unFinishAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractObject, ContractEnum.UN_FINISH_AMOUNT.getAttr(),0D);
                //合同金额
                Double contractAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractObject, ContractEnum.AMOUNT.getAttr(),0D);
                //计算可添加应收款的第三种情况
                Double  contractCanAddMoney = calculateThreeSituation(corpid, contractEntityExt.getId(), contractAmount);
                List<Double> compareList = Arrays.asList(amount, unFinishAmount, contractCanAddMoney);
                amount = Collections.min(compareList);
                if(amount<=BasicConstant.ZERO){
                    return;
                }
                Long executorTime = FastJsonHelper.getLongOrDefaultFromFormData(parentData, ContractOutstockEnum.TIME.getAttr(),0L);
                Long customerId = FastJsonHelper.getLongOrDefaultFromFormData(parentData,ContractOutstockEnum.LINK_CUSTOMER.getAttr(),0L);
                String customerName = FastJsonHelper.getStringOrDefaultFromFormData(parentData,ContractOutstockEnum.LINK_CUSTOMER_HIDE.getAttr(),"");
                String contractName = FastJsonHelper.getStringOrDefaultFromFormData(parentData,ContractOutstockEnum.REF_ID_LINKED_TEXT.getAttr(),"");
                serialNo = saasSaveHelp.getSerialNo(serialNo, corpid, formId, fieldAttrEntity);
                PeriodFilterPojo periodFilterPojo = fundSetService.getPeriodFilter4Payment(corpid,executorTime,customerId,contractId, null);
                AddMuchFieldPojo addMuchFieldPojo = new AddMuchFieldPojo();
                addMuchFieldPojo.setSysLong10(ModelTypeEnum.OUTSTOCK.getCode());
                addMuchFieldPojo.setSerialNo(serialNo);
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(PaymentEnum.AMOUNT.getAttr(), amount);
                jsonObject.put(PaymentEnum.GENERATION_DATE.getAttr(),periodFilterPojo.getGenerationTime());
                JSONObject generationJson = new JSONObject();
                generationJson.put(BasicConstant.TYPE, periodFilterPojo.getType());
                generationJson.put(PeriodTypeEnum.MONTH.getAlias(), periodFilterPojo.getMonth());
                generationJson.put(PeriodTypeEnum.DAY_AFTER.getAlias(), periodFilterPojo.getDay());
                jsonObject.put(PaymentEnum.RECEIVABLE_PERIOD.getAttr(),generationJson.toJSONString());
                jsonObject.put(PaymentEnum.ESTIMATE_TIME.getAttr(),periodFilterPojo.getEstimateTime());
                jsonObject.put(PaymentEnum.SOURCE.getAttr(),paasFormDataEntity.getId());
                jsonObject.put(PaymentEnum.CUSTOMER.getAttr(),customerId);
                jsonObject.put(PaymentEnum.CONTRACT.getAttr(),contractId);
                jsonObject.put(PaymentEnum.STATUS.getAttr(), PaymentStatusEnum.UN_RECEIVABLES.getCode());
                jsonObject.put(PaymentEnum.CUSTOMER_LINK_TEXT.getAttr(),customerName);
                jsonObject.put(PaymentEnum.CONTRACT_LINK_TEXT.getAttr(),contractName);
                jsonObject.put(PaymentEnum.SOURCE_REF_TYPE.getAttr(),refBusinessType);
                jsonObject.put(PaymentEnum.SOURCE_LINK_TEXT.getAttr(),paasFormDataEntity.getSerialNo());
                jsonObject.put(PaymentDistributorEnum.ORDERER_ID.getAttr(), contractObject.get(OrderEnum.ORDERER_ID.getAttr()));
                jsonObject.put(PaymentDistributorEnum.ORDERER.getAttr(), contractObject.get(OrderEnum.ORDERER.getAttr()));
                //初始化其它字段
                for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPayment().entrySet()){
                    SaasDataInitHelp.antDataSet(jsonObject,entry.getKey(),entry.getValue());
                }
                addMuchFieldPojo.setOwnerId(contractEntityExt.getOwnerId());
                addMuchFieldPojo.setData(jsonObject);
                addBatchList.add(addMuchFieldPojo);
                paymentDTO.setAddBatchList(addBatchList);
                //应收款保存
                formDataAddVO = paymentService.pay(paymentDTO);
                isCreatedReceivable = true;

                if(Objects.nonNull(formDataAddVO)){
                    if(CollectionsUtil.isNotEmpty(formDataAddVO.getInsertList())) {
                        //插入对账流水时，需要把出库单的其他费用暂时用该字段暂存（应收款不需要，但是应收生成的对账单需要）
                        Double otherExpense = FastJsonHelper.getDoubleFromFormData(parentData, ContractOutstockEnum.OTHER_EXPENSE.getAttr());
                        // 获取关联产品的数据
                        JSONArray product = FastJsonHelper.getJsonArrOrDefaultFromFormData(parentData, ContractOutstockEnum.PRODUCT.getAttr(),new JSONArray());
                        //插入一条，所以get(0)即可
                        PaasFormDataEntityExt entityExt = formDataAddVO.getInsertList().get(0);
                        JSONObject data = JsonHelperUtil.getJSONObject(entityExt.getData());
                        data.put(BasicConstant.STATEMENT_OTHER_EXPENSE, otherExpense);
                        data.put(BasicConstant.STATEMENT_PRODUCT, product);
                        entityExt.setData(data);
                    }
                }
            }
        }
        if(isCreatedReceivable){
            creatStatement(paymentDTO, businessType, paasFormDataEntity, explainMap, formDataAddVO);
        }
    }

    public void costRecalculationWorkFlow(CostRecalculationDTO costRecalculationDTO)throws XbbException{
        costRecalculationProducer.sendMessage(costRecalculationDTO);
    }
    /**
     * 生成应收款后，同步生成对账单流水
     * @param paymentDTO
     * @param businessType 来源业务的类型
     * @param paasFormDataEntity 来源业务的实体，当手动创建应收模式，该实体为空
     * @param explainMap 应收款解释map
     * @param formDataAddVO 插入应收后的返回vo
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    public void creatStatement(PaymentDTO paymentDTO, Integer businessType, PaasFormDataEntity paasFormDataEntity, Map<String, FieldAttrEntity> explainMap, FormDataAddVO formDataAddVO) throws XbbException {
        if(Objects.nonNull(formDataAddVO) && CollectionsUtil.isNotEmpty(formDataAddVO.getInsertList())){
            List<PaasFormDataEntityExt> paymentInsertList = formDataAddVO.getInsertList();
            String corpid = paymentDTO.getCorpid();
            String errorMsg;
            if (Objects.nonNull(paasFormDataEntity)) {
                errorMsg = "  corpid=" + corpid + " businessType:" + businessType + " (dataId=" + paasFormDataEntity.getId() + ") create statement error";
            } else {
                errorMsg = "  corpid=" + corpid + " businessType:" + businessType + " create statement error";
            }
            try {
                //当为出库产生应收时，该businessType为CONTRACT_OUTSTOCK
                saasCustomerStatementHelper.save(businessType, explainMap, paymentInsertList, paymentDTO.getDistributorMark());
            } catch (XbbException e) {
                List<Long> paymentIdIn = paymentInsertList.stream().map(p -> p.getId()).collect(Collectors.toList());
                customerStatementService.addRollback(corpid, XbbRefTypeEnum.PAYMENT.getCode(), paymentIdIn);
                LOG.error(errorMsg, e);
                throw e;
            } catch (Exception e) {
                List<Long> paymentIdIn = paymentInsertList.stream().map(p -> p.getId()).collect(Collectors.toList());
                customerStatementService.addRollback(corpid, XbbRefTypeEnum.PAYMENT.getCode(), paymentIdIn);
                LOG.error(errorMsg, e);
            }
        }
    }

    /**
     *(1)计算应收款第三种情况的应收款金额：合同金额-(核销预收款金额-红冲核销预收款金额)-(已核销金额-红冲已核销金额)-已坏账金额-（应收款金额-应收款已回款金额-应收款已坏账金额-红冲应收款金额）
     *(2)红冲的单据数据库存的都是负数的，所以下面看的有点奇怪的这边注意一下
     * @param corpid 公司id
     * @param contractId 合同id
     * @param contractAmount 合同金额
     * @return
     */
    private Double calculateThreeSituation(String corpid, Long contractId, double contractAmount) throws XbbException {
        FormDataUpdateGetDTO formDataUpdateGetDTO = new FormDataUpdateGetDTO();
        formDataUpdateGetDTO.setCorpid(corpid);
        formDataUpdateGetDTO.setDataId(contractId);
        //其实是核销的与红冲的一起计算，但是为了直接调用别人方法，这边（1）核销预收款、核销一起计算  （2）红冲核销预收、红冲核销一起计算
        //核销预收款、核销总计
        Double  totalSheetWriteOffAmount = fundMoneyHelp.getSheetTotalWriteOffAmount(XbbRefTypeEnum.PAYMENT_SHEET, formDataUpdateGetDTO, true, true, PaymentSheetEnum.CONTRACT.getAttr());
        //红冲核销预收、红冲核销、坏账总计
        Double  totalSheetRedAndBadAmount = fundMoneyHelp.getSheetRedAndBadAmount(XbbRefTypeEnum.PAYMENT_SHEET,formDataUpdateGetDTO,true,true,PaymentSheetEnum.CONTRACT.getAttr());
        //查询应收款的相关金额
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.CONTRACT), contractId));
        boolQueryBuilder.mustNot(termQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.STATUS),PaymentStatusEnum.RED_RECEIVABLES.getCode()));
        List<String> sumFieldList = Arrays.asList(PaymentEnum.getEsAttr4Keyword(PaymentEnum.REAL_AMOUNT), PaymentEnum.getEsAttr4Keyword(PaymentEnum.BAD_AMOUNT),
                PaymentEnum.getEsAttr4Keyword(PaymentEnum.RED_AMOUNT), PaymentEnum.getEsAttr4Keyword(PaymentEnum.AMOUNT));
        JSONObject jsonObject = esHelper.sumMuchField4Some(IndexTypeEnum.IDX_SAAS_PAYMENT, boolQueryBuilder, sumFieldList);
        //总应收款金额
        double totalAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(jsonObject, PaymentEnum.getEsAttr4Keyword(PaymentEnum.AMOUNT), 0d);
        //总应收款实收金额
        double totalRealAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(jsonObject, PaymentEnum.getEsAttr4Keyword(PaymentEnum.REAL_AMOUNT), 0d);
        //总应收款坏账金额
        double totalBadAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(jsonObject, PaymentEnum.getEsAttr4Keyword(PaymentEnum.BAD_AMOUNT), 0d);
        //总应收款红冲金额
        double totalRedAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(jsonObject, PaymentEnum.getEsAttr4Keyword(PaymentEnum.RED_AMOUNT), 0d);
        double fininalMoney = Arith.add(Arith.sub(totalAmount, Arith.add(totalRealAmount,totalBadAmount)),totalRedAmount);
        // 返回需要的金额
        double needMoney = Arith.sub(Arith.sub(Arith.sub(contractAmount, totalSheetWriteOffAmount), totalSheetRedAndBadAmount), fininalMoney);
        return needMoney;
    }

    public List<PaasFormDataEntityExt> checkReceivablesWhetherCanDel(List<Long> idIn, String corpid, List<Long> errorDataId, List<String> errorDataNo, Set<String> errorTypeSet, Integer businessType) throws XbbException{
        List<PaasFormDataEntityExt> paasFormDataEntityExts = paymentService.getReceivablesBySourceIdIn(corpid,businessType,idIn);
        return checkReceivablesWhetherCanDel(paasFormDataEntityExts, corpid, errorDataId, errorDataNo, errorTypeSet);
    }


    /**
     * 判断应收款下面是否有回款单
     * @param paasFormDataEntityExts
     * @param corpid
     * @param errorDataId
     * @param errorDataNo
     * @param errorTypeSet
     * @return java.util.List<com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt>
     * @throws XbbException
     * @since v1.0
     * @version v1.0
     */
    public List<PaasFormDataEntityExt> checkReceivablesWhetherCanDel(List<PaasFormDataEntityExt> paasFormDataEntityExts, String corpid, List<Long> errorDataId, List<String> errorDataNo, Set<String> errorTypeSet) throws XbbException{
        Map<Long,PaasFormDataEntityExt> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Object> idList = new ArrayList<>();
        HashMap<Long, PaymentTransitionPojo> paymentTransitionPojoHashMap = new HashMap<>(paasFormDataEntityExts.size());
        if (CollectionsUtil.isNotEmpty(paasFormDataEntityExts)) {
            for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                map.put(paasFormDataEntityExt.getId(),paasFormDataEntityExt);
                idList.add(paasFormDataEntityExt.getId());
                PaymentTransitionPojo paymentTransitionPojo = new PaymentTransitionPojo();
                JSONObject jsonObject = paasFormDataEntityExt.getData();
                paymentTransitionPojo.setId(jsonObject.getLong(PaymentEnum.SOURCE.getAttr()));
                paymentTransitionPojo.setSerialNo(jsonObject.getString(PaymentEnum.SOURCE_LINK_TEXT.getAttr()));
                paymentTransitionPojoHashMap.put(paasFormDataEntityExt.getId(), paymentTransitionPojo);
            }
        }
        if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)){
            //这个方案是最安全的
            Map<Long,PaasFormDataEntityExt> refMap =fundHelp.getEsDataMapByLinkIds(XbbRefTypeEnum.PAYMENT_SHEET,corpid,idList, PaymentSheetEnum.PAYMENT.getAttr());
            if(refMap.size() > 0) {
                for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                    if(refMap.containsKey(paasFormDataEntityExt.getId())){
                        if (paymentTransitionPojoHashMap.containsKey(paasFormDataEntityExt.getId())) {
                            PaymentTransitionPojo paymentTransitionPojo = paymentTransitionPojoHashMap.get(paasFormDataEntityExt.getId());
                            errorDataId.add(paymentTransitionPojo.getId());
                            errorDataNo.add(paymentTransitionPojo.getSerialNo());
                            errorTypeSet.add(I18nMessageUtil.getMessage(ErrorMessageConstant.RECEIVABLES_HAS_PAYMENT_SHEET));
                        }
                    }
                }
            }
            return paasFormDataEntityExts;
        }
        return null;
    }

    public void delReceivablesHandle(List<PaasFormDataEntityExt> paasFormDataEntityExts, OperateTypeEnum operateTypeEnum,String userId, String userName, String corpid,String httpHeader) throws XbbException {
        if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)){
            List<Long> receivablesIdList = new ArrayList<>();
            List<String> receivablesNoList = new ArrayList<>();
            paasFormDataEntityExts.forEach(item ->{
                receivablesIdList.add(item.getId());
                receivablesNoList.add(item.getSerialNo());
            });
            try {
                paymentModel.deleteBatch(receivablesIdList,corpid, DelEnum.DELETE.getDel());
                //删除应收的时候需要同时删除对账单,根据应收款id查询出对应的对账单id
                customerStatementService.deleteBatch(corpid, XbbRefTypeEnum.PAYMENT.getCode(), receivablesIdList);
                //生成删除日志(区分单个删除和批量删除)
                String nameStr = StringUtils.join(receivablesNoList, "，");
                if(receivablesIdList.size() > 1){
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_DELETE_FORM_DETAIL), userName, XbbRefTypeEnum.PAYMENT.getName(), receivablesIdList.size());
                    List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    InfoArrPojo infoArrPojo = new InfoArrPojo();
                    infoArrPojo.setTitle(PaymentEnum.PAYMENT_NO.getAttrName());
                    infoArrPojo.setContent(nameStr);
                    infoArrPojoList.add(infoArrPojo);
                    mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, userName, OperateModuleTypeEnum.PaymentManage, operateTypeEnum,
                            "", "", memo,httpHeader);
                } else if (Objects.equals(receivablesIdList.size(), 1)){
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_DELETE_WORK), userName, XbbRefTypeEnum.PAYMENT.getName(), nameStr);
                    mongoLogHelp.buildLog(corpid, userId, userName, OperateModuleTypeEnum.PaymentManage, operateTypeEnum,
                            receivablesIdList.get(0).toString(), nameStr, memo, httpHeader);
                }
            }catch (Exception e) {
                threadPoolBeanConfig.addUpdateDelThreadPool().execute(() -> {
                    try{
                        //线程睡眠的目的是为了让数据库能回滚完成
                        Thread.sleep(1000L);
                        if (CollectionUtils.isNotEmpty(receivablesIdList)) {
                            paymentService.updateRollback(receivablesIdList, corpid);
                        }
                        customerStatementService.updateRollback(corpid, XbbRefTypeEnum.PAYMENT.getCode(), receivablesIdList);
                    } catch (XbbException | InterruptedException e1) {
                        LOG.error("delReceivablesHandle rollback" + e1);
                        // 恢复中断状态
                        Thread.currentThread().interrupt();
                    }
                });
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
            }
        }
    }
}
